package com.hushan.standby.compoment;

import cn.hutool.system.OsInfo;
import cn.hutool.system.SystemUtil;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import static com.hushan.standby.App.*;

public class VirtualIPControl {

    public static boolean isIpAddressBound(String interfaceName, String ipAddress) {
        String[] commands;
        OsInfo osInfo = SystemUtil.getOsInfo();

        if (osInfo.isWindows()) {
            commands = new String[]{"powershell.exe", "-Command", "ipconfig /all"};
        } else if (osInfo.isLinux()) {
            commands = new String[]{"ip", "addr", "show", interfaceName};
        } else if (osInfo.isMac()) {
            commands = new String[]{"ifconfig", interfaceName};
        } else {
            throw new UnsupportedOperationException("Unsupported OS: " + osInfo.getName());
        }

        boolean foundInterface = false;
        boolean foundIpAddress = false;

        try {
            Process process = Runtime.getRuntime().exec(commands);

            String charset = osInfo.isWindows() ? "GBK" : "UTF-8";
            BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream(), charset));
            BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream(), charset));

            String s;
            while ((s = stdInput.readLine()) != null) {
                if (s.contains(interfaceName)) {
                    foundInterface = true;
                }
                if (s.contains(ipAddress)) {
                    foundIpAddress = true;
                }
            }

            while ((s = stdError.readLine()) != null) {
                System.out.println(s);
            }

            int exitValue = process.waitFor();
            if (exitValue != 0) {
                throw new RuntimeException("Failed to execute command: " + String.join(" ", commands));
            }

            if (foundInterface && foundIpAddress) {
                System.out.println("网卡 " + interfaceName + " 已绑定 IP 地址 " + ipAddress);
                return true;
            } else {
                System.out.println("网卡 " + interfaceName + " 未绑定 IP 地址 " + ipAddress);
                return false;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return foundInterface;
    }

    private static boolean addVirtualIPElevated(String interfaceName, String ipAddress, String subnetMask, String gateway) {
        if (isIpAddressBound(interfaceName, ipAddress)) {
            VirtualIPControl.removeVirtualIPElevated(VIRTUAL_INTERFACE_NAME, VIRTUAL_IP);
        }
        System.out.println("尝试添加虚拟 IP: " + VIRTUAL_IP + " 到接口: " + VIRTUAL_INTERFACE_NAME);
        OsInfo osInfo = SystemUtil.getOsInfo();
        String command;
        if (osInfo.isWindows()) {
            command = String.format("netsh interface ip add address name=\"%s\" addr=%s mask=%s gateway=%s st=ac",
                    interfaceName, ipAddress, subnetMask, gateway);
        } else if (osInfo.isLinux()) {
            command = String.format("ip addr add %s/%s dev %s", ipAddress, getPrefixLength(subnetMask), interfaceName);
        } else if (osInfo.isMac()) {
            command = String.format("ifconfig %s %s netmask %s", interfaceName, ipAddress, subnetMask);
        } else {
            throw new UnsupportedOperationException("Unsupported OS: " + osInfo.getName());
        }
        return executeElevatedCommand(command, "已添加");
    }

    public static boolean removeVirtualIPElevated(String interfaceName, String ipAddress) {
        OsInfo osInfo = SystemUtil.getOsInfo();
        String command;
        if (osInfo.isWindows()) {
            command = String.format("netsh interface ip delete address name=\"%s\" addr=%s", interfaceName, ipAddress);
        } else if (osInfo.isLinux()) {
            command = String.format("ip addr del %s dev %s", ipAddress, interfaceName);
        } else if (osInfo.isMac()) {
            command = String.format("ifconfig %s %s", interfaceName, "delete");
        } else {
            throw new UnsupportedOperationException("Unsupported OS: " + osInfo.getName());
        }
        return executeElevatedCommand(command, "已删除");
    }

    private static boolean executeElevatedCommand(String command, String successKeyword) {
        boolean success = false;
        Process process = null;
        BufferedReader reader = null;
        StringBuilder stdoutOutput = new StringBuilder();
        StringBuilder stderrOutput = new StringBuilder();
        int exitCode = -1;

        try {
            String[] commands;
            OsInfo osInfo = SystemUtil.getOsInfo();

            if (osInfo.isWindows7()) {
                commands = new String[]{"powershell.exe", "-Command", command};
            } else if (osInfo.isWindows()) {
                String psCommand = String.format(
                        "Start-Process powershell -ArgumentList '%s ; $LASTEXITCODE' -Verb RunAs -Wait -PassThru",
                        command
                );
                commands = new String[]{"powershell.exe", "-Command", psCommand};
            } else {
                commands = new String[]{"sudo", "sh", "-c", command};
            }

            ProcessBuilder pb = new ProcessBuilder(commands);
            process = pb.start();

            BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"));
            String stdoutLine;
            while ((stdoutLine = stdoutReader.readLine()) != null) {
                stdoutOutput.append(stdoutLine).append("\n");
                if (stdoutLine.contains(successKeyword)) {
                    success = true;
                }
                try {
                    int potentialExitCode = Integer.parseInt(stdoutLine.trim());
                    if (potentialExitCode >= 0) {
                        exitCode = potentialExitCode;
                    }
                } catch (NumberFormatException ignored) {
                }
            }

            BufferedReader stderrReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "GBK"));
            String stderrLine;
            while ((stderrLine = stderrReader.readLine()) != null) {
                stderrOutput.append(stderrLine).append("\n");
            }

            int waitForExit = process.waitFor();
            if (waitForExit == 0 || success || stdoutOutput.toString().contains("对象已存在。") || stderrOutput.toString().contains("对象已存在。")) {
                return true;
            } else {
                if (!stderrOutput.isEmpty()) {
                    System.err.println("错误信息:\n" + stderrOutput.toString());
                }
                return false;
            }

        } catch (IOException | InterruptedException e) {
            System.err.println("执行命令时发生异常，请确保程序以管理员身份运行。");
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (reader != null) reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (process != null) process.destroy();
        }
    }

    private static String getPrefixLength(String subnetMask) {
        int count = 0;
        for (String octet : subnetMask.split("\\.")) {
            int value = Integer.parseInt(octet);
            while (value > 0) {
                count += value & 1;
                value >>= 1;
            }
        }
        return String.valueOf(count);
    }

    public static void stopSlave() {
        if (!VirtualIPControl.addVirtualIPElevated(VIRTUAL_INTERFACE_NAME, VIRTUAL_IP, VIRTUAL_MASK, VIRTUAL_GATEWAY)) {
            System.err.println("虚拟 IP 添加操作失败。");
        }
    }

    public static void startSlave() {
        if (!isIpAddressBound(VIRTUAL_INTERFACE_NAME, VIRTUAL_IP)) {
            return;
        }
        if (VirtualIPControl.removeVirtualIPElevated(VIRTUAL_INTERFACE_NAME, VIRTUAL_IP)) {
            System.out.println("虚拟 IP 删除成功。");
        } else {
            System.err.println("虚拟 IP 删除失败.");
        }
    }


    public static boolean isIpAddressBound_win11(String interfaceName, String ipAddress) {
        String[] commands;
        OsInfo osInfo = SystemUtil.getOsInfo();

        if (osInfo.isWindows() && osInfo.getName().contains("11")) {
            commands = new String[]{"powershell.exe", "-Command", "netsh interface ip show config"};
        } else {
            return false;
        }

        boolean foundInterface = false;
        boolean foundIpAddress = false;

        try {
            Process process = Runtime.getRuntime().exec(commands);

            String charset = "UTF-8";
            BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream(), charset));
            BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream(), charset));

            String s;
            while ((s = stdInput.readLine()) != null) {
                if (s.contains(interfaceName)) {
                    foundInterface = true;
                }
                if (s.contains(ipAddress)) {
                    foundIpAddress = true;
                }
            }

            while ((s = stdError.readLine()) != null) {
                System.out.println(s);
            }

            int exitValue = process.waitFor();
            if (exitValue != 0) {
                throw new RuntimeException("Failed to execute command: " + String.join(" ", commands));
            }

            if (foundInterface && foundIpAddress) {
                System.out.println("网卡 " + interfaceName + " 已绑定 IP 地址 " + ipAddress);
                return true;
            } else {
                System.out.println("网卡 " + interfaceName + " 未绑定 IP 地址 " + ipAddress);
                return false;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return foundInterface;
    }
}
